package com.example.server.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.example.dao.deptMapper.DeptMapper;
import com.example.dao.userMapper.UserMapper;
import com.example.dto.dept.Dept;
import com.example.dto.dept.DeptCriteria;
import com.example.dto.job.Job;
import com.example.dto.menu.Menu;
import com.example.dto.role.Role;
import com.example.exception.BadRequestException;
import com.example.server.DeptServer;
import com.example.util.DateUtil;
import com.example.util.ValidationUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class DeptServerImpl implements DeptServer {

    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private UserMapper userMapper;

    /**
     * 查询部门
     *
     * @param
     * @return Map<String, Object>
     */
    @Override
    public List<Dept> list(DeptCriteria deptCriteria) {

        Map<String, Object> code = new HashMap<>();
        code.put("createTime", deptCriteria.getCreateTime());
        code.put("updateTime",null);
        code.put("name", deptCriteria.getName());
        code.put("enabled", deptCriteria.getEnabled());
        code.put("pid", deptCriteria.getPid());
        List<Dept> depts = deptMapper.selectList(code);
        int count = deptMapper.findCount(code);
        List<Dept> results = buildTrees(depts);
        //向results集合中的每个menu对象中设置hasChildren
        results.forEach(x -> {
            Long menuId = x.getId();
            boolean isChild = this.isChildren(menuId);
            x.setHasChildren(isChild);
            x.setLabel(x.getName());
        });
        return results;
    }

    private boolean isChildren(Long id) {
        int count = deptMapper.findCounts(id);
        return count > 0;
    }

    public List<Dept> buildTrees(List<Dept> deptDtos) {
        List<Dept> trees = new ArrayList<>();
        Set<Long> ids = new HashSet<>();
        for (Dept deptDTO : deptDtos) {
            if (deptDTO.getPid() == null) {
                trees.add(deptDTO);
            }
            for (Dept it : deptDtos) {
                if (deptDTO.getId().equals(it.getPid())) {
                    if (deptDTO.getChildren() == null) {
                        deptDTO.setChildren(new ArrayList<>());
                    }
//                    deptDTO.getChildren().add(it);
                    ids.add(it.getId());
                }
            }
        }
        if (trees.size() == 0) {
            trees = deptDtos.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList());
        }
        return trees;
    }

    @Override
    public List<Dept> getSuperior(Dept deptDto, List<Dept> depts) {
        if (deptDto.getPid() == null) {
            deptDto.setLabel(deptDto.getName());
            depts.addAll(deptMapper.findByPidIsNull());
            depts.forEach(x -> {
                x.setLabel(x.getName());
            });
            return depts;
        }
        depts.addAll(deptMapper.findByPid(deptDto.getPid()));
        return getSuperior(findById(deptDto.getPid()), depts);
    }

    @Override
    public Object buildTree(List<Dept> deptDtos) {
        Set<Dept> trees = new LinkedHashSet<>();
        Set<Dept> depts = new LinkedHashSet<>();

        List<String> deptNames = deptDtos.stream().map(Dept::getName).collect(Collectors.toList());
        boolean isChild;
        for (Dept deptDTO : deptDtos) {
            isChild = false;
            if (deptDTO.getPid() == null) {
                trees.add(deptDTO);
            }
            for (Dept it : deptDtos) {
                if (it.getPid() != null && deptDTO.getId().equals(it.getPid())) {
                    isChild = true;
                    if (deptDTO.getChildren() == null) {
                        deptDTO.setChildren(new ArrayList<>());
                    }
                    deptDTO.getChildren().add(it);
                }
            }
            if (isChild) {
                depts.add(deptDTO);
            } else if (deptDTO.getPid() != null && !deptNames.contains(findById(deptDTO.getPid()).getName())) {
                depts.add(deptDTO);
            }
        }

        if (CollectionUtil.isEmpty(trees)) {
            trees = depts;
        }
        Map<String, Object> map = new HashMap<>(2);
        map.put("totalElements", deptDtos.size());
        map.put("content", CollectionUtil.isEmpty(trees) ? deptDtos : trees);
        return map;
    }

    @Override
    public List<Long> getDeptChildren(List<Dept> deptList) {
        List<Long> list = new ArrayList<>();
        deptList.forEach(dept -> {
                    if (dept != null && dept.getEnabled()) {
                        List<Dept> depts = deptMapper.findByPid(dept.getId());
                        if (depts.size() != 0) {
                            list.addAll(getDeptChildren(depts));
                        }
                        list.add(dept.getId());
                    }
                }
        );
        return list;
    }


    /**
     * 增加部门
     *
     * @param dept 部门参数
     * @return Map<String, Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(Dept resources) {
        deptMapper.save(resources);
        // 计算子节点数目
        resources.setSubCount(0);
        // 清理缓存
        updateSubCnt(resources.getPid());
    }

    /**
     * 删除部门
     *
     * @param
     * @return Map<String, Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Dept> deptDtos) {
        for (Dept deptDto : deptDtos) {
            deptMapper.findById(deptDto.getId());
            updateSubCnt(deptDto.getPid());
        }
    }

    private void updateSubCnt(Long deptId) {
        if (deptId != null) {
            int count = deptMapper.countByPid(deptId);
            deptMapper.updateSubCntById(count, deptId);
        }
    }

    @Override
    public Dept findById(Long id) {
        Dept dept = deptMapper.findByIds(id);
        dept.setLabel(dept.getName());
        ValidationUtil.isNull(dept.getId(), "Dept", "id", id);
        return dept;
    }

    @Override
    public Set<Dept> getDeleteDepts(List<Dept> menuList, Set<Dept> deptDtos) {
        for (Dept dept : menuList) {
            deptDtos.add(dept);
            List<Dept> depts = deptMapper.findByPid(dept.getId());
            if (depts != null && depts.size() != 0) {
                getDeleteDepts(depts, deptDtos);
            }
        }
        return deptDtos;
    }

    /**
     * 修改部门信息
     *
     * @param dept 部门参数
     * @return Map<String, Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Dept resources) {
        // 旧的部门
        Long oldPid = findById(resources.getId()).getPid();
        Long newPid = resources.getPid();
        if (resources.getPid() != null && resources.getId().equals(resources.getPid())) {
            throw new BadRequestException("上级不能为自己");
        }
        Dept dept = deptMapper.findByIds(resources.getId());
        ValidationUtil.isNull(dept.getId(), "Dept", "id", resources.getId());
        resources.setId(dept.getId());
        deptMapper.save(resources);
        // 更新父节点中子节点数目
        updateSubCnt(oldPid);
        updateSubCnt(newPid);
    }

    @Override
    public List<Dept> findByPid(long pid) {
        return deptMapper.findByPid(pid);
    }
}
